CanvasRenderingContext2D.prototype.roundRect =
    function (x, y, width, height, radius, fill, stroke) {
        if (typeof stroke === "undefined") {
            stroke = true;
        }
        if (typeof radius === "undefined") {
            radius = 5;
        }
        this.beginPath();
        this.moveTo(x + radius, y);
        this.lineTo(x + width - radius, y);
        this.quadraticCurveTo(x + width, y, x + width, y + radius);
        this.lineTo(x + width, y + height - radius);
        this.quadraticCurveTo(x + width, y + height, x + width - radius, y+ height);
        this.lineTo(x + radius, y + height);
        this.quadraticCurveTo(x, y + height, x, y + height - radius);
        this.lineTo(x, y + radius);
        this.quadraticCurveTo(x, y, x + radius, y);
        this.closePath();
        if (stroke) {
            this.stroke();
        }
        if (fill) {
            this.fill();
        }
    };
(function (window, undefined) {
    var engine = function (c) {

        if (c.engine !== null) {
            return c.engine;
        }

        var that,
            canvas = c,
            cOffset = canvas.offset(),
            context = canvas.get(0).getContext("2d"),
            frames = 33,
            objs = [],
            clearCanvas = function () {
                canvas.attr("width", canvas.width());
                canvas.attr("height", canvas.height());
            },
            paint = function(context, obj){
                obj.runMotion();

                context.save();
                if(obj.repaint !== undefined) {
                    obj.repaint(context);
                }
                context.restore();

                // paint children
                var i,
                    l = obj.children.length;
                if (l > 0) {
                    for (i = 0; i < l; i++) {
                        paint(context, obj.children[i]);
                    }
                }
            },
            animation = function () {
                clearCanvas();

                that.nowFrame = new Date().getTime();
                that.deltaTime = (that.nowFrame - that.lastFrame) / 1000;
                that.lastFrame = that.nowFrame;

                var i;
                for (i = 0; i < objs.length; i += 1) {
                    paint(context, objs[i]);
                }

                setTimeout(function () {
                    animation();
                }, frames);
            },
            checkClick = function(obj, pos){
                if (obj.onClick !== undefined && isClick(obj, pos)) {
                    obj.onClick(pos);
                }

                var l = obj.children.length;
                if (l > 0) {
                    for (var i = 0; i < l; i++) {
                        checkClick(obj.children[i], pos);
                    }
                }
            },
            isClick = function(obj, pos){
                return obj.getGlobalX() < pos.x &&
                    (obj.getGlobalX() + obj.width) > pos.x &&
                    obj.getGlobalY() < pos.y &&
                    (obj.getGlobalY() + obj.height) > pos.y;
            },
            getClickPos = function(e){
                return { x: e.clientX - cOffset.left, y: e.clientY - cOffset.top };
            };

        canvas.click(function (e) {
            for(var i = 0; i < objs.length; i++) {
                checkClick(objs[i], getClickPos(e));
            }
        });

        that = {};

        that.version = "1.0";
        that.init = function () {
            canvas.engine = that;
            that.lastFrame = new Date().getTime();

            animation();

            return that;
        };

        that.add = function (object) {
            if(object !== null && object !== undefined) {
                objs.push(object);
            }

            return that;
        };

        that.remove = function (index) {
            if (typeof index === "number"){
                index = Math.ceil(index);
                objs.splice(index, 1);
            } else if (typeof index === "object"){
                for (var i = 0; i < objs.length; i++) {
                    if (objs[i]  === index) {
                        objs.splice(i, 1);
                    }
                }
            }


        };

        that.get = function (index) {
            return objs[index];
        };

        //engine.fn = engine.prototype = {
        //    version: "1.0",
        //    constructor: engine,
        //    init : function(){
        //        canvas.engine = this;
        //        this.lastFrame = new Date().getTime();
        //
        //        animation();
        //
        //        return this;
        //    },
        //    add : function(object){
        //        if(object !== null && object !== undefined) {
        //            objs.push(object);
        //        }
        //
        //        return this;
        //    },
        //    remove : function(index){
        //        if (typeof index === "number"){
        //            index = Math.ceil(index);
        //            objs.splice(index, 1);
        //        } else if (typeof index === "object"){
        //            for (var i = 0; i < objs.length; i++) {
        //                if (objs[i]  === index) {
        //                    objs.splice(i, 1);
        //                }
        //            }
        //        }
        //    },
        //    get : function(index){
        //        return _get(index);
        //    }
        //}

        //engine.fn.init.prototype = engine.fn;



        return that.init();
    };

    engine.define = function (fn) {
        if (typeof fn === "function") {
            var templFn = function () {
                this.x = 0;
                this.y = 0;
                this.width = 0;
                this.height = 0;
                this.children = [];
                this.parent = null;
                this.motionFuns = [];
                this.repaint = function(){};

                fn.apply(this, Array.prototype.slice.call(arguments));
            }
            templFn.prototype = fn.prototype;

            templFn.prototype.addChild = function (child) {
                // TODO coordinate x and y to local Coordinate relative to parent

                child.parent = this;
                this.children.push(child);
                return this;
            }
            templFn.prototype.getGlobalX = function () {
                if (this.parent === undefined) {
                    throw new Error("can not read parent property.");
                }
                if (this.parent !== null) {
                    return this.x + this.parent.getGlobalX();
                } else {
                    return this.x;
                }
            }
            templFn.prototype.getGlobalY = function () {
                if (this.parent === undefined) {
                    throw new Error("can not read parent property.");
                }
                if (this.parent != null) {
                    return this.y + this.parent.getGlobalY();
                } else {
                    return this.y;
                }
            }
            templFn.prototype.addMotionFun = function (name, fun) {
                this.motionFuns[name] = fun;
            }
            templFn.prototype.removeMotionFun = function (name) {
                this.motionFuns[name] = null;
            }
            templFn.prototype.runMotion = function () {
                for (var key in this.motionFuns) {
                    if (this.motionFuns[key] === null)
                        continue;
                    this.motionFuns[key].call(this);
                }
            }
            return templFn;
        }
    }

    window.EngineY = engine;

}(window));